#pragma once

#include "Thread.hpp"
#include "LockGuard.hpp"
#include "Task.hpp"
#include "Log.hpp"
#include <queue>
#include <vector>
#include <iostream>
#include <unistd.h>

using namespace ThreadMoudle;
using namespace LogMoudle;

// 默认的线程池中线程的数量
static const int g_thread_num = 5;

// 测试函数
void Test(std::string &name)
{
    while (true)
    {
        std::cout << name << " hello world" << std::endl;
        sleep(1);
    }
}

template <class T>
class ThreadPool
{
private:
    void LockQueue()
    {
        pthread_mutex_lock(&_mutex);
    }

    void UnLockQueue()
    {
        pthread_mutex_unlock(&_mutex);
    }

    void WakeUp()
    {
        pthread_cond_signal(&_cond);
    }

    void WakeUpAll()
    {
        pthread_cond_broadcast(&_cond);
    }

    bool IsEmpty()
    {
        return _task_queue.empty();
    }

    void Sleep()
    {
        pthread_cond_wait(&_cond, &_mutex);
    }

    void HandlerTask(std::string &name)
    {
        while (true)
        {
            LockQueue();
            while (IsEmpty() && _is_running)
            {
                _sleep_thread_num++;
                LOG(INFO, "%s sleep begin!\n", name.c_str());
                Sleep();
                LOG(INFO, "%s  wakeup!\n", name.c_str());
                _sleep_thread_num--;
            }
            // 如果任务队列为空，且线程池的状态是 false 就说明退出了
            if (IsEmpty() && !_is_running)
            {
                UnLockQueue();
                LOG(INFO, "%s  quit...!\n", name.c_str());
                break;
            }
            // 取任务
            T t = _task_queue.front();
            _task_queue.pop();
            UnLockQueue();
            // 处理数据,这里不能放在临界区
            t();
            LOG(DEBUG, "handler task done, task is: %s\n", t.result().c_str());
        }
    }

    // 单例模式
    ThreadPool(int thread_num = g_thread_num)
        : _thread_num(thread_num)
        , _sleep_thread_num(0)
        , _is_running(false)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }

    // 禁用掉 赋值拷贝和拷贝构造
    ThreadPool(const ThreadPool<T> &tp) = delete;
    void operator=(const ThreadPool<T> &tp) = delete;

public:
    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }

    static ThreadPool<T> *GetInstance()
    {
        if (_tp == nullptr)
        {

            LockGuard lockguard(&_sig_mutex);
            if (_tp == nullptr)
            {
                LOG(INFO, "Create ThreadPool!\n");
                _tp = new ThreadPool<T>();
                _tp->Init();
                _tp->Start();
            }
            else
            {
                LOG(INFO, "Get ThreadPool!\n");
            }
        }

        return _tp;
    }

    // 初始化线程库
    void Init()
    {
        for (int i = 0; i < _thread_num; i++)
        {
            func_t func = std::bind(&ThreadPool::HandlerTask, this, std::placeholders::_1);
            std::string thread_name = "thread_" + std::to_string(i + 1);
            _threads.emplace_back(thread_name, func);
            LOG(DEBUG, "construct  %s done, init success!\n", thread_name.c_str());
        }
    }

    // 启动线程库中的线程
    void Start()
    {
        _is_running = true;
        for (auto &t : _threads)
        {
            t.Start();
            LOG(DEBUG, "%s start done\n", t.Name().c_str());
        }
    }

    // 终止线程库中的线程
    void Stop()
    {
        LOG(DEBUG, "thread pool stop success!\n");
        LockQueue();
        _is_running = false;
        WakeUpAll();
        UnLockQueue();
    }

    // 向任务队列中推送任务
    void Equeue(const T &in)
    {
        LockQueue();
        if (_is_running)
        {
            _task_queue.push(in);
            if (_sleep_thread_num > 0)
                WakeUp();
        }
        UnLockQueue();
    }

private:
    int _thread_num;              // 线程的个数
    std::vector<Thread> _threads; // 组织线程的数组
    std::queue<T> _task_queue;    // 任务队列
    bool _is_running;             // 线程池的状态
    int _sleep_thread_num;        // 线程池中休眠线程的状态

    pthread_mutex_t _mutex; // 互斥锁
    pthread_cond_t _cond;   // 条件变量

    static ThreadPool<T> *_tp;         // 单例模式
    static pthread_mutex_t _sig_mutex; // 单例锁
};

// 初始化
template <class T>
ThreadPool<T> *ThreadPool<T>::_tp = nullptr;

template <class T>
pthread_mutex_t ThreadPool<T>::_sig_mutex = PTHREAD_MUTEX_INITIALIZER;